use crate::M3u8Item;


#[cfg(test)]
mod test{
    use std::borrow::Borrow;
    use std::fmt::format;
    use std::io::Read;
    use std::mem::discriminant;
    use std::num::ParseIntError;
    use std::ops::Deref;
    use std::sync::Arc;
    use std::sync::Condvar;
    use std::sync::Mutex;
    use std::sync::OnceLock;
    use std::sync::atomic::AtomicU32;
    use std::sync::atomic::Ordering;
    use std::thread;
    use std::time::Duration;

    use m3u8_rs::Playlist;
    use tokio::runtime::Runtime;

    use super::M3u8Item;

    enum Signal{
        Normal,
        Pause,
        End,
    }

    #[test]
    fn test_rw_lock(){
        let lock = std::sync::RwLock::new(12);
        { //读锁；获取多个读锁不会阻塞
            let r1 = lock.read().unwrap();
            let r2 = lock.read().unwrap();
            println!("r1 = {:?}", r1);
            println!("r2 = {:?}", r2);
        }
        
        let arc_lock = Arc::new(lock);
        { //写锁
            let clone_lock = arc_lock.clone();
            std::thread::spawn(move ||{
                let mut w = clone_lock.write().unwrap();
                *w = 90;
                std::thread::sleep(Duration::from_secs(5));
                println!("===> 子线程释放锁")
            });

            std::thread::sleep(Duration::from_millis(500));
            
            //写锁 未释放时获取读锁会阻塞
            let r = arc_lock.read().unwrap();
            println!("r1 = {:?}", r);
        }
        println!("r = {:?}", arc_lock.read().unwrap());
    }
    #[test]
    fn test_atomic(){
        let counter = Arc::new(AtomicU32::new(100));
        let counter_c = counter.clone();
        let joiner= thread::spawn(move ||{
            for _ in 0..1000{
                counter_c.fetch_add(1, Ordering::Relaxed);
            }
        });

        for _ in 0..1000{
            counter.fetch_add(1, Ordering::Relaxed);
        }
        joiner.join();

        println!("atomic = {:?}", counter);
        assert_eq!(counter.load(Ordering::Relaxed), 2100);
    }
    #[test]
    fn test_lazy(){
        static lock: OnceLock<i32> = std::sync::OnceLock::new();
        let lock_ref = lock.get_or_init(||{
            //初始化只会被执行一次
            println!("初始化1");
            99
        });
        let lock_ref_2 = lock.get_or_init(||{
            println!("初始化2");
            99
        });
        println!("lock_ref = {:?}", lock);
    }
    #[test]
    fn test_tuple(){
        // let (mut a, mut b) = (1, 2);
        let mut a = 1;
        let mut b = 2;
        println!("a={},b={}", a, b);
        //通过元组交换值
        (a,b) = (b,a);
        println!("a={},b={}", a, b);
    }
    #[test]
    fn test_enum(){
        // 只有 没有内部值的枚举才能使用as 转换成整数
        println!("signal idx = {:?}", Signal::Normal as usize);
        println!("signal idx = {:?}", Signal::Pause as usize);

        println!("discriminant(Normal) idx = {:?}", discriminant(&Signal::Normal));
        println!("discriminant(Pause) idx = {:?}", discriminant(&Signal::Pause));

        #[derive(PartialEq,Debug)]
        enum Testenum{
            A,
            B(i32),
            C(f32)
        }
        println!("discriminant(A) idx = {:?}", discriminant(&Testenum::A));
        // 相同类型的枚举 discriminant值也是相同的，即使包含的内部值不同
        println!("discriminant(B(10)) idx = {:?}", discriminant(&Testenum::B(10)));
        println!("discriminant(B(20)) idx = {:?}", discriminant(&Testenum::B(20)));
        println!("discriminant(C(20f32)) idx = {:?}", discriminant(&Testenum::C(20f32)));
        println!("discriminant(C(40f32)) idx = {:?}", discriminant(&Testenum::C(40f32)));

        assert_eq!(discriminant(&Testenum::B(10)), discriminant(&Testenum::B(20)));
        assert_eq!(Testenum::B(10), Testenum::B(20));

    }
    /// Condvar用来主动阻塞和 唤醒线程
    /// Condvar.wait(guard) 阻塞线程
    /// Condvar.notify_all(guard) 唤醒等待这个条件的线程
    /// 可以用来实现CountDownLatch门闩工具
    #[test]
    fn test_condvar(){
        println!("begin....");
        let cond = std::sync::Condvar::new();
        let b = false;

        let pair: Arc<(Mutex<bool>, Condvar)> = Arc::new((Mutex::new(b),cond));
        let p2 = pair.clone();
        std::thread::spawn(move ||{
            println!("进入子线程");
            thread::sleep(Duration::from_secs(5));
            let mut guard = p2.0.lock().unwrap();
            *guard = true;
            p2.1.notify_all();
            println!("释放锁");
        });

        
        let mut guard = pair.0.lock().unwrap();
        while !*guard {
            guard = pair.1.wait(guard).unwrap();
            println!("重新获取锁");
        }
        println!("program end... guard:{}", *guard);
    }
    #[test]
    fn test_pattern(){
        let a=(1,2);
        match a{
            (x,y) if x >=1 =>{

            },
            _=>{}
        }
        struct S{
            num: i32
        };
        /// @匹配 只能用于结构体，限定
        /// 成员变量的值，相当于简化if语句
        let s = S{num:10};
        match s{
            S{num: num2 @0..=3} =>{
                println!("num={}",num2);
            }
            _=>{}
        }

        /// 为常量绑定一个值(Rust 1.53 新增)
        match 1 {
            n @ 1=>{}
            n @ 2=>{}
            num @ (3 | 4) => {
                println!("{}", num);
            }
            _ => {}
        }
        ///前绑定后解构(Rust 1.56 新增)
        #[derive(Debug)]
        struct Point {
            x: i32,
            y: i32,
        }
        /// 绑定新变量 `p`，同时对 `Point` 进行解构
        let p @ Point {x: px, y: py } = Point {x: 10, y: 23};
        println!("x: {}, y: {}", px, py);
        println!("{:?}", p);


        let point = Point {x: 10, y: 5};
        if let p @ Point {x: 10, y} = point {
            println!("x is 10 and y is {} in {:?}", y, p);
        } else {
            println!("x was not 10 :(");
        }
    }
    /// join的 使用 和 Borrow的使用
    #[test]
    fn test_join(){
        #[derive(Debug)]
        struct Point<'a> {
            x: &'a [i32],
        }
    
        impl Borrow<[i32]> for Point<'_> {
            fn borrow(&self) -> &[i32] {
                &self.x
            }
        }

        
        // 所有切片实现了 Join trait， 
        // 只要切片元素 V 实现了 Borrow<[T]> trait 即 V 可以转成 T的切片
        // 就可以调用 join(&T) 方法, 传入一个T 的引用，返回一个T的vec
        let mut v = vec![Point { x: &[1, 2] }, Point { x: &[5,6] }];
        let join_res = v.join(&3);
        println!("join_res = {:?}", join_res);

        for e  in v.iter_mut() {
            (*e).x = &[3,4];
        }

        // 非字符串类型想要 拼接成字符串 可以 先map collect成 vec<String> 再join
        let rres = v.iter().map(|f|format!("{:?}", f))
            .collect::<Vec<String>>()
            .join(",");

        println!("rres = {:?}", rres);
    }
    #[test]
    fn test_m3u8_rs(){
        let mut file = std::fs::File::open("data.m3u8").unwrap();
        let mut bytes: Vec<u8> = Vec::new();
        file.read_to_end(&mut bytes).unwrap();

        let parsed = m3u8_rs::parse_playlist_res(&bytes);

        match parsed {
            Ok(Playlist::MasterPlaylist(pl)) => println!("Master playlist:\n{:?}", pl),
            Ok(Playlist::MediaPlaylist(pl)) => {
                println!("Media playlist");
                let version = pl.version;
                let end = pl.end_list;
                let max_duration = pl.target_duration;
                let play_type = pl.playlist_type;
                let segs = pl.segments;
                println!("version: {:?}, end: {}, max_duration: {}, plat_type: {:?}, segs size: {:?}", 
                    version, end, max_duration, play_type, segs.len());
                println!("first seg : {:?}", segs[0]);
            },
            Err(e) => println!("Error: {:?}", e),
        }
    }
    #[test]
    fn test_m3u8_parser(){
        //解析的比较原始，
        // 只对标签进行了解析，没有对标签进行结构化，iv 、切片地址也没有体现出来
        let play_list = m3u8_parser::m3u8::playlist::Playlist::from_file("data.m3u8").unwrap();
        println!("play_list = {:?}", play_list);
    }
}